package com.muzi.onvif;

import com.muzi.onvif.PTZ.requset.AbsoluteMoveRequest;
import com.muzi.onvif.PTZ.requset.ContinuousMoveRequest;
import com.muzi.onvif.PTZ.requset.GetStatusRequest;
import com.muzi.onvif.PTZ.requset.StopRequest;
import com.muzi.onvif.beans.OnvifDevice;
import com.muzi.onvif.beans.PTZPanTilt;
import com.muzi.onvif.imaging.MoveOnvifRequest;
import com.muzi.onvif.media.request.GetProfilesOnvifRequest;
import com.muzi.onvif.media.request.GetSnapshotUriRequest;
import com.muzi.onvif.util.OnvifUtils;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.poi.util.IOUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.*;

public class OnvifIpChanger {

    private static final Map<String, String> cookies = new HashMap<>();

    public static void main(String[] args) {
        OnvifDevice device = new OnvifDevice();
        device.setIp("192.168.10.104");
        device.setUsername("admin");
        device.setPassword("abc12345");
        absoluteMove(device,"0","0");
//        absoluteMoveZoom(device,"-0.671333","0.382000","-0.671333");
//        imagingMove(device,"0","0");
//        ptzStop(device);
//        PTZPanTilt panTilt = getStatus(device);
//        System.out.println(panTilt.getX()+":"+panTilt.getY()+":"+panTilt.getZ());


    }

    public static boolean continuousMove(OnvifDevice device,String x,String y,String z){
        List<String> profileTokens = getProfileToken(device);
        if (profileTokens!=null&&profileTokens.size()>0){
            return continuousMove(device,profileTokens.get(0),x,y,z);
        }
        return false;

    }
    public static boolean imagingMove(OnvifDevice device,String speed){
        List<String> videoSourceToken = getVideoSourceToken(device);
        if (videoSourceToken!=null&&videoSourceToken.size()>0){
            return imagingMove(device,videoSourceToken.get(0),speed);
        }
        return false;

    }

    public static boolean imagingMove(OnvifDevice device,String videoSourceToken,String speed){
        String xmlString = OnvifUtils.sendMessage(device.getUrl(),new MoveOnvifRequest().getXml(device,videoSourceToken,speed));
        //将给定的String文本解析为XML文档并返回新创建的document
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlString);
            //获取根节点,在例子中就是responsedata节点
            Element rootElement = document.getRootElement().element("Body");
            Iterator i = rootElement.elementIterator("MoveResponse");
            if (i.hasNext()){
                return true;
            }else {
                System.out.println("MoveResponse Error :"+rootElement.element("Fault").element("Reason").element("Text").getStringValue());
                return false;
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return false;
    }

    public static boolean continuousMove(OnvifDevice device,String profileToken,String x,String y,String z){
        String xmlString = OnvifUtils.sendMessage(device.getUrl(),new ContinuousMoveRequest().getXml(device,profileToken,x,y,z));
        //将给定的String文本解析为XML文档并返回新创建的document
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlString);
            //获取根节点,在例子中就是responsedata节点
            Element rootElement = document.getRootElement().element("Body");
            Iterator i = rootElement.elementIterator("ContinuousMoveResponse");
            if (i.hasNext()){
                return true;
            }else {
                System.out.println("continuousMove Error :"+rootElement.element("Fault").element("Reason").element("Text").getStringValue());
                return false;
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return false;

    }

    public static boolean ptzStop(OnvifDevice device){
        List<String> profileTokens = getProfileToken(device);
        if (profileTokens!=null&&profileTokens.size()>0){
            return ptzStop(device,profileTokens.get(0));
        }
        return false;
    }

    public static boolean ptzStop(OnvifDevice device,String profileToken){
        String xmlString = OnvifUtils.sendMessage(device.getUrl(),new StopRequest().getXml(device,profileToken));
        //将给定的String文本解析为XML文档并返回新创建的document
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlString);
            //获取根节点,在例子中就是responsedata节点
            Element rootElement = document.getRootElement().element("Body");
            Iterator i = rootElement.elementIterator("StopResponse");
            if (i.hasNext()){
                return true;
            }else {
                System.out.println("Stop Error :"+rootElement.element("Fault").element("Reason").element("Text").getStringValue());
                return false;
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * *摄像头抓图(获取url)
     * @param device
     * @return
     */
    public static String getSnapshotUri(OnvifDevice device){
        List<String> profileTokens = getProfileToken(device);
        if (profileTokens!=null&&profileTokens.size()>0){
            return getSnapshotUri(device,profileTokens.get(0));
        }
        return "";
    }
    public static String getSnapshotUri(OnvifDevice device,String profileToken){

        String xmlString = OnvifUtils.sendMessage(device.getUrl(),new GetSnapshotUriRequest().getXml(device,profileToken));
        //将给定的String文本解析为XML文档并返回新创建的document
        String url = "";
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlString);
            //获取根节点,在例子中就是responsedata节点
            Element rootElement = document.getRootElement().element("Body")
                    .element("GetSnapshotUriResponse")
                    .element("MediaUri")
                    .element("Uri");
            url = rootElement.getStringValue();
            StringBuilder stringBuilder = new StringBuilder(url);
            stringBuilder.insert(7,device.getUsername()+":"+device.getPassword()+"@");
            System.out.println("url: "+stringBuilder.toString());
            return stringBuilder.toString();
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return url;
    }

    @Async
    public static boolean absoluteMove(OnvifDevice device,String x,String y){
        List<String> profileTokens = getProfileToken(device);
        if (profileTokens!=null&&profileTokens.size()>0){
            return absoluteMove(device,profileTokens.get(0),x,y);
        }
        return false;
    }



    public static boolean absoluteMoveZoom(OnvifDevice device,String x,String y,String z){
        List<String> profileTokens = getProfileToken(device);
        if (profileTokens!=null&&profileTokens.size()>0){
            return absoluteMove(device,profileTokens.get(0),x,y,z);
        }
        return false;
    }

    //转向
    public static boolean absoluteMove(OnvifDevice device,String profileToken,String x,String y){
        String xmlString = OnvifUtils.sendMessage(device.getUrl(),new AbsoluteMoveRequest().getXml(device,profileToken,x,y));
        //将给定的String文本解析为XML文档并返回新创建的document
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlString);
            //获取根节点,在例子中就是responsedata节点
            Element rootElement = document.getRootElement().element("Body");
            Iterator i = rootElement.elementIterator("AbsoluteMoveResponse");
            if (i.hasNext()){
                return true;
            }else {
                System.out.println("absoluteMove Error :"+rootElement.element("Fault").element("Reason").element("Text").getStringValue());
                return false;
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return false;
    }

    //转向+zoom
    public static boolean absoluteMove(OnvifDevice device,String profileToken,String x,String y,String z){
        String xmlString = OnvifUtils.sendMessage(device.getUrl(),new AbsoluteMoveRequest().getXml(device,profileToken,x,y,z));
        //将给定的String文本解析为XML文档并返回新创建的document
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlString);
            //获取根节点,在例子中就是responsedata节点
            Element rootElement = document.getRootElement().element("Body");
            Iterator i = rootElement.elementIterator("AbsoluteMoveResponse");
            if (i.hasNext()){
                return true;
            }else {
                System.out.println("absoluteMove Error :"+rootElement.element("Fault").element("Reason").element("Text").getStringValue());
                return false;
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return false;
    }

    public static PTZPanTilt getStatus(OnvifDevice device){
        List<String> profileTokens = getProfileToken(device);
        if (profileTokens!=null&&profileTokens.size()>0){
            return getStatus(device,profileTokens.get(0));
        }
        return null;
    }

    public static PTZPanTilt getStatus(OnvifDevice device, String profileToken){
        String xmlString = OnvifUtils.sendMessage(device.getUrl(),new GetStatusRequest().getXml(device,profileToken));
        PTZPanTilt panTilt = new PTZPanTilt();

        //将给定的String文本解析为XML文档并返回新创建的document
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlString);
            //获取根节点,在例子中就是responsedata节点
            Element rootElement = document.getRootElement().element("Body");
            Iterator i = rootElement.elementIterator("GetStatusResponse");
            if (i.hasNext()){
                Element rootPanTilt = document.getRootElement().element("Body").element("GetStatusResponse").element("PTZStatus").element("Position").element("PanTilt");
                Element rootZoom = document.getRootElement().element("Body").element("GetStatusResponse").element("PTZStatus").element("Position").element("Zoom");
                panTilt.setX(rootPanTilt.attribute("x").getValue());
                panTilt.setY(rootPanTilt.attribute("y").getValue());
                panTilt.setZ(rootZoom.attribute("x").getValue());
                return panTilt;
            }else {
                System.out.println("GetStatus Error :"+rootElement.element("Fault").element("Reason").element("Text").getStringValue());

            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return panTilt;

    }
    //获取ProfileToken
    public static List<String> getProfileToken(OnvifDevice device){
        List<String> profileTokens = new ArrayList<>();
        String xmlString = OnvifUtils.sendMessage(device.getUrl(),new GetProfilesOnvifRequest().getXml(device));
        //将给定的String文本解析为XML文档并返回新创建的document
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlString);
            //获取根节点,在例子中就是responsedata节点
            Element rootElement = document.getRootElement().element("Body").element("GetProfilesResponse");
            for (Iterator profilesNext = rootElement.elementIterator("Profiles"); profilesNext.hasNext(); ){
                Element profiles = (Element) profilesNext.next();
//                System.out.println(profiles.attribute("token").getValue());
                Iterator i = profiles.elementIterator("PTZConfiguration");
                if (i.hasNext()){
                    profileTokens.add(profiles.attribute("token").getValue());
                }

            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }

        return profileTokens;
    }

    //获取ProfileToken
    public static List<String> getVideoSourceToken(OnvifDevice device){
        List<String> profileTokens = new ArrayList<>();
        String xmlString = OnvifUtils.sendMessage(device.getUrl(),new GetProfilesOnvifRequest().getXml(device));
        //将给定的String文本解析为XML文档并返回新创建的document
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlString);
            //获取根节点,在例子中就是responsedata节点
            Element rootElement = document.getRootElement().element("Body").element("GetProfilesResponse");
            for (Iterator profilesNext = rootElement.elementIterator("Profiles"); profilesNext.hasNext(); ){
                Element profiles = (Element) profilesNext.next();
//                System.out.println(profiles.attribute("token").getValue());
                profileTokens.add(profiles.element("VideoSourceConfiguration").element("SourceToken").getStringValue());
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }

        return profileTokens;
    }

    public static String send(String url,String username,String password){
        if (cookies.containsKey(url)){
            return cookies.get(url);
        }else {
            URL authRequest = null;
            try {
                authRequest = new URL(url);
                HttpURLConnection conn = (HttpURLConnection) authRequest.openConnection();
                conn.setRequestMethod("GET");
                //直接调用一次让接口生成摘要认证需要使用的认证信息
                String wwwAuthenticate = conn.getHeaderField("WWW-Authenticate");
                String[] wwwAuthenticateTemp = wwwAuthenticate.split(",");
                Map<String, String> wwwAuthenticateMap = new HashMap<>();
                for (String s : wwwAuthenticateTemp) {
                    String[] temp = s.split("=");
                    wwwAuthenticateMap.put(temp[0].trim().replace("\"", ""), temp[1].trim().replace("\"", ""));
                }
                String qop = wwwAuthenticateMap.get("qop");
                String digestRealm = wwwAuthenticateMap.get("Digest realm");
                String nonce = wwwAuthenticateMap.get("nonce");
                String algorithm = wwwAuthenticateMap.get("algorithm");
                String clientNonce = UUID.randomUUID().toString().replace("-", "");
                String ha1 = DigestUtils.md5Hex(username + ":" + digestRealm + ":" + password);
                String ha2 = DigestUtils.md5Hex("GET" + ":" + url);
                String response = DigestUtils.md5Hex(ha1 + ":" + nonce + ":00000001:" + clientNonce + ":" + qop + ":" + ha2);
                String authorization = "Digest username=\"" + username + "\", realm=\"" + digestRealm
                        + "\", nonce=\"" + nonce + "\", uri=\"" + url + "\", algorithm=\"" + algorithm + "\""
                        + ", qop=" + qop + ",nc=00000001, cnonce=\"" + clientNonce + "\", response=\"" + response + "\", opaque=\"";
                cookies.put(url,authorization);
                return authorization;
            } catch (Exception e) {
                e.printStackTrace();
            }

        }


        return null;

    }

    public static MultipartFile saveFile(String urls, String username, String password){
        // 输出的文件流
        String path = System.getProperty("user.dir");
        File pathFile = new File(path);
        // 格式化时间
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HHmmssSSS");
        String format = simpleDateFormat.format(new Date());
        String filename = path + "/" + format + ".jpg";
        File file = new File(filename);

        try {
            // 构造URL
            URL url = new URL(urls);
            // 打开连接
            URLConnection con = url.openConnection();
            //获取图片认证
            con.setRequestProperty("Authorization", send(urls,username,password));

            if (!pathFile.exists()) {
                pathFile.mkdirs();
            }
            // 1k的缓冲数据
            byte[] bs = new byte[1024];
            // 阅读到的数据长度
            int len;
            // 获取输入流
            InputStream inputStream = con.getInputStream();
            // 开始读取
            FileOutputStream outputStream = new FileOutputStream(file, true);
            while ((len = inputStream.read(bs)) != -1) {
                outputStream.write(bs, 0, len);
            }

            inputStream.close();
            outputStream.close();
            return getMultipartFile(file);
        }catch (Exception e){
            //报错 清除cookies
            cookies.remove(urls);
            System.out.println(e.getMessage());
        }
        return null;
    }
    public static MultipartFile getMultipartFile(File file) {
        FileItem item = new DiskFileItemFactory().createItem("file"
                , MediaType.MULTIPART_FORM_DATA_VALUE
                , true
                , file.getName());
        try (InputStream input = new FileInputStream(file);
             OutputStream os = item.getOutputStream()) {
            // 流转移
            IOUtils.copy(input, os);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid file: " + e, e);
        }
        file.delete();
        return new CommonsMultipartFile(item);
    }




}
